<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>AI 对话模式 - WebIM UI 主题演示</title>
    <link href="/layuim/demo/layui/css/layui.css" rel="stylesheet">
    <link href="/layuim/demo/css/demo.css" rel="stylesheet">
</head>
<body>

<div class="layui-panel demo-menu">
    <h1>稽查AI助手</h1>
    <ul class="layui-menu" id="demo-menu">
        <li class="layui-menu-item-divider"></li>
        <li class="layui-menu-item-checked">
            <div class="layui-menu-body-title">
                <a href="/index/aizs">AI 对话模式</a>
            </div>
        </li>
    </ul>
</div>

<script>
    if (!/^http(s*):\/\//.test(location.href)) alert('请通过 localhost 访问该页面');
</script>

<script src="/layuim/demo/layui/layui.js"></script>

<!-- 引入外部公共 CDN 的依赖库（用于演示），亦可下载到本地引入 -->
<script src="/layuim/demo/js/markdown-it.min.js"></script>
<script src="/layuim/demo/js/index.min.js"></script>

<script type="module">
    const {fetchEventSource} = FetchEventSource;

    // 加载核心组件
    layui.config({
        layimPath: '/layuim/dist/', // 配置 layim.js 所在目录
        layimResPath: '/layuim/dist/res/', // layim 资源文件所在目录
        version: '4.0.1'
    }).extend({
        layim: layui.cache.layimPath + 'layim' //  配置 layim 组件所在的路径
    }).use('layim', function (layim) {
        // 基础配置
        layim.config({
            contactsPanel: false, // 不开启联系人面板
            init: {
                user: { // 配置当前用户信息
                    "username": "沈阳市税务局稽查局选案科-李润东", // 我的昵称
                    "id": "12101620140" // 我的 ID
                }
            }
        });


        // 定义快捷语映射表
        let shortcutReplyMap = {};

        layui.$.getJSON('/layuim/demo/json/shortcutReplyMap.json', function(data) {
            shortcutReplyMap = data;
        });
        // 扩展聊天工具栏
        layim.extendChatTools([
            {
                name: 'shortcut',
                title: '快捷语',
                icon: 'layui-icon-list',
                onClick: function (obj) {
                    layui.dropdown.render({
                        elem: obj.elem,
                        data: [
                            {title: '中华人民共和国增值税法'},
                            {title: '国务院办公厅关于健全基本医疗保险参保长效机制的指导意见'},
                            {title: '互联网平台企业涉税信息报送规定'},
                            {title: 'AI稽查助手都有哪些功能'},
                            {title: '超期3个月正在执行的案件都有哪些？'}
                        ],
                        show: true,
                        click: function (data) {
                            // obj.insert(data.title); // 将文本插入到编辑器
                            layim.sendMessage(data.title) // 直接发送消息
                        }
                    })
                }
            }
        ]);
        /**
         * 自定义内容解析器
         * AI 一般返回 markdown 格式的内容，您可借助第三方 markdown 解析器渲染 AI 返回的内容
         * 常用的 markdown 解析器有：marked, markdown-it
         *
         * 请注意：
         * 1. markdown 解析器应禁用 HTML 标签（通常为默认），避免 XSS，确保返回安全的 HTML 内容
         * 2. 若不采用 markdown 解析器，请务必自行转义 XSS 字符
         *
         * 下面以使用 markdown-it 为例
         * @see https://markdown-it.github.io/markdown-it/value
         */
        layim.callback('contentParser', content => {
            const md = markdownit({
                typographer: true,
                linkify: true,
                breaks: true
            });
            return md.render(content); // 将 markdown 字符渲染成 HTML
        });

        // 事件 - 发送消息
        layim.on('sendMessage', function (data) {
            const user = data.user; // 我
            const receiver = data.receiver; // 对方
            const content = user.content;
            const rid = receiver.id;

            console.log(data)


            // ✅ 判断是否为快捷语
            if (receiver.type === 'ai' && shortcutReplyMap[content]) {
                // 是快捷语，直接返回固定回复
                setTimeout(() => {
                    layim.getMessage({
                        ...receiver,
                        content: shortcutReplyMap[content],
                        finished: true
                    });
                }, 3000); // 模拟延迟
                return; // 结束当前事件，不再往下执行
            }
            // AI 对话模式
            if (receiver.type === 'ai') {
                async function render() {
                    // 模拟演示 AI 接口，实际使用时可将下述 setTimeout 换成 Ajax, Fetch API, EventSource 的任意一种
                    async function requestDemo(callback) {
                        setTimeout(() => {
                            callback('您好，我是稽查AI小助手，致力于为您提供高效、智能的业务支持。\n\n我可以为您提供以下服务：\n- ' +
                                '快速查询稽查政策、法规依据\n- 辅助撰写检查报告、文书模板\n- 解析表格数据、提供处理建议\n- ' +
                                '回答稽查流程相关问题，节省人工沟通成本\n\n本系统已接入阿里云「通义千问」大模型，确保响应及时、内容权威。' +
                                '\n欢迎您向我提问，提升您的工作效率！');
                        }, 1000);
                    }

                    /**
                     * 以下分别演示采用「事件流」和「jQuery Ajax」方式请求阿里云「通义千问」接口
                     * 阿里「通义千问」@see https://help.aliyun.com/zh/dashscope/developer-reference/
                     * 百度「千帆大模型」@see https://cloud.baidu.com/doc/WENXINWORKSHOP/s/6ltgkzya5
                     *
                     * 请注意 ⚡：
                     *   1. 以下代码仅用于演示，请勿直接用于生产环境。
                     *   2. 实际开发时，请务必将请求大模型的接口代码写在后端，避免在浏览器端直接暴露 API_KEY, SECRET_KEY。
                     */
                    async function requestQwen(callback) {
                        const API_URL = 'https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation';
                        const API_KEY = document.querySelector('#QWEN_API_KEY').value;
                        const API_MODEL = document.querySelector('#QWEN_MODEL').value;

                        // 交互方式
                        const QWEN_REQUEST_MODE = document.querySelector('#QWEN_REQUEST_MODE').value;

                        // 基础参数
                        const options = {
                            method: 'POST',
                            headers: {
                                "Authorization": `Bearer ${API_KEY}`,
                                "Content-Type": "application/json"
                            },
                            body: JSON.stringify({
                                model: API_MODEL, // 模型
                                input: {
                                    messages: messages[rid]
                                },
                                parameters: {
                                    temperature: 1.3,
                                    top_p: 0.9,
                                    max_tokens: 1500,
                                }
                            })
                        };

                        // 事件流交互方式
                        if (QWEN_REQUEST_MODE === 'stream') {
                            const eventSource = await fetchEventSource(API_URL, {
                                ...options,
                                onopen(response) {
                                    if (!response.ok) {
                                        throw new Error(`URL ${response.status} ${response.statusText}`)
                                    }
                                },
                                onmessage(event) {
                                    // console.log(event);
                                    const {data, id} = event;
                                    const {output} = data;
                                    const finished = output.finish_reason === 'stop';

                                    let text = output.text + ((finished || id % 2) ? '' : ' _');
                                    if (typeof callback === 'function') {
                                        callback(text, finished);
                                    }

                                    // 将回复内容加入到多轮对话
                                    if (finished) {
                                        messages[rid].push({
                                            role: 'assistant',
                                            content: text
                                        });
                                    }
                                },
                                onerror(error) {
                                    callback(`**Error**: ${error}`);
                                }
                            });
                            // console.log(eventSource
                        } else if (QWEN_REQUEST_MODE === 'ajax') { // 传统 jQuery Ajax 交互方式
                            options.data = options.body;
                            delete options.body;

                            layui.$.ajax({
                                ...options,
                                url: API_URL,
                                success(data) {
                                    // console.log(data);
                                    const {output} = data;
                                    const finished = output.finish_reason === 'stop';
                                    let text = output.text;

                                    if (typeof callback === 'function') {
                                        callback(text, finished);
                                    }

                                    // 将回复内容加入到多轮对话
                                    messages[rid].push({
                                        role: 'assistant',
                                        content: text
                                    });
                                },
                                error(error) {
                                    callback(`**Error**: ${error.responseText}`);
                                }
                            });
                        }

                    }

                    // 多轮对话
                    const rid = receiver.id;
                    const messages = layim.chat.messages = layim.chat.messages || {
                        [rid]: []
                    };
                    messages[rid] = messages[rid] || []
                    messages[rid].push({
                        role: 'user',
                        content: user.content
                    });

                    // 测试方式
                    // const testMode = document.querySelector('[name="testMode"]:checked').value;
                    const testMode = "requestDemo";
                    console.log("testMode", testMode);
                    const requests = {requestDemo};
                    typeof requestQwen === 'function' && (requests.requestQwen = requestQwen);

                    // 获得 AI 回复内容
                    requests[testMode]((content, finished) => {
                        // layim 接受对话消息
                        layim.getMessage({
                            ...receiver,
                            content: content,
                            finished
                        });
                    });
                }

                return render();
            }
        });

        // 聊天面板初始打开的事件
        layim.on('chatInit', function (obj) {
            const data = obj.data;
            const elem = obj.elem;
            if (data.type === 'ai') {
                // 每次刷新页面，即提示为新的对话
                const lastItem = elem.find('.layim-chat-main>ul>li').last();
                const existMessages = layim.chat.messages && layim.chat.messages[data.id];
                if (!existMessages && !lastItem.hasClass('layim-chat-system')) {
                    layim.getMessage({
                        system: true,
                        id: data.id,
                        type: 'ai',
                        content: '以下为新的对话',
                        // saveLocalChatlog: true // 是否将该消息保存到本地的聊天记录
                    });
                }
            }
        });

        /**
         * 其他操作
         */
        const {$, util, form} = layui;

        // 创建 AI 对话
        const createAIChat = {
            // 普通 AI 对话面板
            normal() {
                layim.chat({
                    username: 'AI 助手测试',
                    type: 'ai', // AI 模式
                    avatar: '', // 头像
                    id: 1,
                    new: true, // 始终创建新的聊天面板
                    layer: {
                        maxmin: false // 不显示最大/小化图标
                    }
                });
            },
            // 最大化 AI 对话面板
            max({username = '稽查AI助手', id = 1, enableLocalChatlog = true} = {}) {
                layim.chat({
                    username: username,
                    type: 'ai', // AI 模式
                    avatar: '', // 头像
                    id: id,
                    new: true, // 始终创建新的聊天面板
                    enableLocalChatlog,
                    layer: {
                        move: false,
                        offset: 'r',
                        maxmin: false
                    },
                    success(layero, index) {
                        // 重置弹层样式
                        layer.style(index, {
                            top: 0,
                            left: '151px', // 同侧边菜单占用的宽度
                            right: 0,
                            width: 'auto',
                            height: '100%'
                        }, true);
                        // 让聊天内容区域高度自适应
                        layero.find('.layim-chat-main').css({
                            height: 'calc(100vh - 202px)' // 此处 202 为标题和底部输入框占用的高度
                        })
                    }
                });
            }
        };

        // 面板外的操作示例事件
        util.on({
            ...createAIChat,
            max() {
                createAIChat.max()
            },
            // 创建随机 AI 对话
            random() {
                const id = Math.floor(Math.random() * 99999999); // 生成随机 id
                createAIChat.max({
                    username: `AI 助手测试@${id}`,
                    id,
                    enableLocalChatlog: false // 不启用本地聊天记录
                });
            }
        });

        // 测试方式 - radio 事件
        form.on('radio(testMode)', function (data) {
            var elem = data.elem; // 获得 radio 原始 DOM 对象
            var value = elem.value; // 获得 radio 值
            $(`.demo-test-tabs-body > [set="${value}"]`).show().siblings().hide();
        })

        // ✅ ✅ 页面一加载就打开最大化对话窗口
        createAIChat.max();
    });
</script>
</body>
</html>
